import { _decorator, Component, easing, tween, Vec2, Vec3 } from 'cc';
const {ccclass, property} = _decorator;

import PolygonNav2D from "./PolygonNav2D";

@ccclass('PolygonNavAgent')
export default class PolygonNavAgent extends Component{
	private _polygonNav2D:PolygonNav2D;
	private _targetPos:Vec2;
	private _currentPos:Vec2 = new Vec2();
	private _currentPath:Vec2[] = [];
	private _isMove:boolean = false;
	private _maxSpeed = 200;
	private _dir = 1;
	private _isInAdjustPos = false;
	public get Dir()
	{
		{ return this._dir;}
	}
	private _velocity:Vec2 = new Vec2();
	public get Velocity()
	{
		{ return this._velocity;}
	}
	public set Velocity(value:Vec2)
	{
		{ this._velocity = value;}
	}
	
	public get CurrentPath(){return this._currentPath;}
	public set CurrentPath(value:Vec2[]){this._currentPath = value;}
	public get IsMove(){return this._isMove;}
	public Init(polygonNav2D:PolygonNav2D, pos:Vec2)
	{
		this._polygonNav2D = polygonNav2D;
		this._isInAdjustPos = false;
		this.SetPos(pos);
	}

	public SetPos(pos:Vec2)
	{
		this._currentPos = pos;
		this.node.setPosition(new Vec3(pos.x, pos.y));
	}

	public set Speed(value:number)
	{
		this._maxSpeed = value;
	}

	public SetTargetPos(targetPos:Vec2):boolean
	{
		if (this._polygonNav2D == null)
		{
			return false;
		}

		if(this._isMove)
		{
			if (Vec2.squaredDistance(targetPos, this._targetPos) < Number.EPSILON)
			{
				return true;
			}
		}

		this._targetPos = targetPos;
		if (Vec2.squaredDistance(targetPos, this._currentPos) < Number.EPSILON)
		{
			this.Stop();
			return false;
		}
		if (!this._polygonNav2D.PointIsValid(targetPos))
		{
			return this.SetTargetPos(this._polygonNav2D.GetCloserEdgePoint(targetPos));
		}

		this._currentPath = [];
		if (!this._polygonNav2D.PointIsValid(this._currentPos))
		{
			this._currentPos = this._polygonNav2D.GetCloserEdgePoint(this._currentPos);
		}
		this._polygonNav2D.FindPath(this._currentPos, targetPos, this._currentPath);
		if(this._currentPath.length == 0)
		{
			this.Stop();
			return false;
		}
		else
		{
			this._isMove = true;
			return true;
		}

	}

	public SetDirPos (dir:Vec2, time:number) 
	{
		this.Stop();
		let targetPos = this._currentPos.add(dir.normalize().multiplyScalar(this._maxSpeed * time));
		if(this._polygonNav2D.PointIsValid(targetPos))
		{
			this._currentPos.set(targetPos);
		}
		else 
		{
			this._currentPos.set(this._polygonNav2D.GetCloserEdgePoint(targetPos))
		}
		this.node.setPosition(new Vec3(this._currentPos.x, this._currentPos.y));
		this._velocity.set(dir);
		this.RefreshDir();
	}

	public Stop()
	{
		this._currentPath = [];
		this._isMove = false;
		this._targetPos = null;
		let pos = this.node.position;
		this._currentPos.set(pos.x, pos.y);
	}

	public get HasPath()
	{
		{ return this._currentPath.length > 0;}
	}

	public get NextPoint()
	{
		{ return this.HasPath? this._currentPath[0] : this._currentPos; }
	}

	protected update(dt: number): void {
        if (this.HasPath)
        {
			this._isMove = true;
			if(!this._isInAdjustPos)
			{
				let s = this._maxSpeed * dt
				this._currentPos.set(this.Seek(this._currentPos, this.NextPoint, s));
				this.node.setPosition(new Vec3(this._currentPos.x, this._currentPos.y));
			}
		}
		else
		{
			this._isMove = false;
        }
	}

	private RefreshDir()
	{
		if (this._velocity.x < 0) 
		{  
        	this._dir = -1;
        } 
		else if (this._velocity.x > 0) {
        	this._dir = 1;
		}  
	}
	
	private Seek(pos:Vec2, nextPos:Vec2, maxDis:number):Vec2
	{
		let disToTarget = Vec2.distance(pos, nextPos);
		if(disToTarget < maxDis)
		{
			maxDis -= disToTarget;
			if(this._currentPath.length > 1)
			{
				this._currentPath.shift();
				return this.Seek(nextPos, this.NextPoint, maxDis);
			}
			else
			{
				this._currentPath.shift();
				Vec2.subtract(this._velocity, nextPos, pos); 
				return nextPos;
			}
		}
		else
		{
			Vec2.subtract(this._velocity, nextPos, pos);  
			this.RefreshDir();
	  
			this._velocity.normalize().multiplyScalar(maxDis);  
			let newPosition = new Vec2(); 
			Vec2.add(newPosition, pos, this._velocity); pos.add(this._velocity);  
			return newPosition;  
		}
	}

	//添加障碍物刷新
	public AdjustPos()
	{
		this._isInAdjustPos = true;
	}

	public AdjustPosEnd()
	{
		this._isInAdjustPos = false;
	}
}

